#!/usr/bin/env python
# -*- coding: utf-8 -*-

# Copyright (C) 2007 Rodrigo Amaral
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any later
# version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 51
# Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

"""Chico The Chimp is really a silly game. Its main purpose is to be an example of how to 
put together all Pygame little pieces"""

import pygame, sys, os
from pygame.locals import *

import random as Random

BG_COLOR = (0, 0, 0)
FIELD_COLOR = (255, 255, 255)
SIDEBAR_COLOR = (127, 127, 127)
DEFAULT_SCREEN_SIZE = (640, 480)
RESOURCE_DIR = 'res'

class Game(object):
    def __init__(self, **kwargs):        
        self.run = True        
        pygame.init()                
        pygame.key.set_repeat(50, 50)  
        screen_size = kwargs['screen_size']        
        field_size = (screen_size[1], screen_size[1])        
        window = pygame.display.set_mode(screen_size) 

        caption = kwargs['caption']
        if caption:
            pygame.display.set_caption(caption)
        
        self.screen = pygame.display.get_surface()
        self.screen.fill(BG_COLOR)
        
        self.field = pygame.Surface(field_size)
        self.field = self.field.convert()
        self.field.fill(FIELD_COLOR)
        
        self.sidebar = pygame.Surface((screen_size[0] - field_size[0], screen_size[1] / 5))
        self.sidebar = self.sidebar.convert()
        self.sidebar.fill(SIDEBAR_COLOR)
        
        self.monkey = Monkey()
        self.score = Score(self.monkey)
        
        self.allsprites = {
            "monkey": pygame.sprite.RenderUpdates(self.monkey),
            "bananas": pygame.sprite.RenderUpdates(self.game_object_factory(Banana)),
            "plants": pygame.sprite.RenderUpdates(self.game_object_factory(CarnivorousPlant)),
            "sprays": pygame.sprite.RenderUpdates(),
        }

    def game_object_factory(self, game_object_class):
        """Creates a game object in a random position of the field"""
        
        field_size = self.field.get_size()
        x = Random.randint(0, field_size[0])
        y = Random.randint(0, field_size[1])
        pos = (x, y)
        return game_object_class(pos)
    
    def handle_event(self, events):
        """Takes care of all allowed key inputs and other events"""
        
        for event in events:
            t = event.type
            if t == QUIT:
                self.end()
            elif t in (KEYDOWN, KEYUP):                
                k = event.key
                if t == KEYDOWN:
                    if k == K_RIGHT:
                        self.monkey.walk_east(self.field)
                    elif k == K_LEFT:
                        self.monkey.walk_west(self.field)
                    elif k == K_UP:
                        self.monkey.walk_north(self.field)
                    elif k == K_DOWN:
                        self.monkey.walk_south(self.field)
                    elif k in (K_KP_PLUS, K_PLUS):
                        self.monkey.go_faster()
                    elif k in (K_KP_MINUS, K_MINUS):
                        self.monkey.go_slower()
                    elif k == K_SPACE:
                        if self.monkey.use_spray():
                            self.kill_plants()
                    elif k == K_ESCAPE:
                        self.end()
    
    def loop(self):
        """Calls the game main loop"""
        
        while self.run:            
            self.handle_event(pygame.event.get())
            self.process_actions()
            self.update_scene()

    def update_scene(self):
        """Updates and redraws background and all game objects"""
        
        self.allsprites.update()                
        self.screen.blit(self.field, (0, 0))        # blitting the bg to cover last scene
        self.score.draw(self.screen, self.sidebar)  # updating score
        for element in self.allsprites.values():
            element.draw(self.screen)
        pygame.display.flip()                       # updating the whole screen
        
    def process_actions(self):
        """Process game rules when the player touchs an object"""
        
        touched_plants = pygame.sprite.spritecollide(self.monkey, self.allsprites['plants'], 1)
        if touched_plants:
            self.monkey.touch_plant()            
            
        eaten_bananas = pygame.sprite.spritecollide(self.monkey, self.allsprites['bananas'], 1)
        if eaten_bananas:
            self.monkey.eat()
            self.allsprites['bananas'].add(self.game_object_factory(Banana))
            self.allsprites['plants'].add(self.game_object_factory(CarnivorousPlant))
            if self.show_herbicide():
                self.allsprites['sprays'].add(self.game_object_factory(Spray))
                
        collected_cans = pygame.sprite.spritecollide(self.monkey, self.allsprites['sprays'], 1)
        if collected_cans:
            self.monkey.grab_spray()

    def end(self):
        """Finishes the game"""
        
        sys.exit(0)

    def show_herbicide(self, difficulty_level=10):
        """Randomly shows spray cans. Raising the difficulty level makes herbicide cans
        take longer to show up"""
        
        turn_value = Random.randint(1, difficulty_level)
        return (turn_value % difficulty_level == 0)
    
    def kill_plants(self):
        self.allsprites['plants'].empty()
    
class Score(object):
    """Renders the score panel"""
    
    font_size = 18
    
    def __init__(self, player):
        self.player = player
        self.font = pygame.font.SysFont("Arial", Score.font_size)
        
    def draw(self, screen, sidebar):        
        banana_score = self.font.render("Bananas: %d" % self.player.banana_count, 1, (255, 255, 255, 0))        
        spray_score = self.font.render("Herbicidas: %d" % self.player.spray_count, 1, (255, 255, 255, 0))
        screen.blit(sidebar, (480, 0))  # blitting the bg to cover last score
        screen.blit(banana_score, (485, 5))
        screen.blit(spray_score, (485, self.font.get_height() + 5))
        
    
class GameObject(pygame.sprite.Sprite):
    """Base class for all sprite elements"""
    
    def __init__(self, image, position):
        pygame.sprite.Sprite.__init__(self)
        
        self.image = image
        
        if isinstance(self.image, str):                        
            self.image = os.path.join(RESOURCE_DIR, self.image)
            self.image = pygame.image.load(self.image)
        
        self.rect  = self.image.get_rect()
        self.last_rect = self.rect
        self.set_pos(position)
    
    def get_pos(self):
        return (self.rect.center[0], self.rect.bottom)

    def set_pos(self, pos):
        self.rect.center = (pos[0], pos[1])
    
    def draw(self, screen):
        screen.blit(self.image, self.rect)
   
    def is_inside(self, screen):
        return screen.get_rect().contains(self.rect)
 
class Monkey(GameObject):
    
    STEP = 10
    
    def __init__(self):
        GameObject.__init__(self, "monkey.png", (320, 240))
        
        self.banana_count = 0
        self.plant_count = 0
        self.spray_count = 0
        
        self.chomp = ChompSound()
        self.scream = ScreamSound()
        self.spray = SpraySound()
        self.boing = BoingSound()

    def walk_north(self, screen):
        self.walk(screen, (0, -Monkey.STEP))
    
    def walk_east(self, screen):
        self.walk(screen, (Monkey.STEP, 0))            
   
    def walk_south(self, screen):
        self.walk(screen, (0, Monkey.STEP))

    def walk_west(self, screen):
        self.walk(screen, (-Monkey.STEP, 0))
    
    def walk(self, screen, pos):
        if self.is_inside(screen):
            self.last_rect = self.rect
            self.rect = self.rect.move(pos[0], pos[1])
        else:
            self.rect = self.last_rect
    
    def go_faster(self):
        """Makes the player walk faster by increasing the "step" size"""
        if Monkey.STEP < 30:
            Monkey.STEP +=1
    
    def go_slower(self):
        """Makes the player walk slower by decreasing the "step" size"""
        if Monkey.STEP > 1:
            Monkey.STEP -=1
            
    def eat(self):
        """Called when the monkey eats a banana"""
        
        self.chomp.play()
        self.banana_count += 1
        
    def touch_plant(self):
        """Called when the monkey touchs a carnivorous plant"""
                
        self.scream.play() 
        self.plant_count += 1
    
    def grab_spray(self):
        """Called when the monkey picks up a spray can"""
        
        self.boing.play()
        self.spray_count += 1
        
    def use_spray(self):
        """Called when the monkey uses a spray can"""
                
        if self.spray_count > 0:
            self.spray.play()
            self.spray_count -= 1
            return True
        return False
            
class Banana(GameObject):
    def __init__(self, position):
        GameObject.__init__(self, "banana.png", position)
        
class CarnivorousPlant(GameObject):
    def __init__(self, position):
        GameObject.__init__(self, "carnivore.gif", position)
        
class Spray(GameObject):
    def __init__(self, position):
        GameObject.__init__(self, "spray.png", position)
        
        
class ChompSound(pygame.mixer.Sound):
    def __init__(self):                    
        pygame.mixer.Sound.__init__(self, os.path.join(RESOURCE_DIR, 'chomp.wav'))
    
class ScreamSound(pygame.mixer.Sound):
    def __init__(self):                    
        pygame.mixer.Sound.__init__(self, os.path.join(RESOURCE_DIR, 'doh.wav'))        

class SpraySound(pygame.mixer.Sound):
    def __init__(self):                    
        pygame.mixer.Sound.__init__(self, os.path.join(RESOURCE_DIR, 'spray.wav'))        

class BoingSound(pygame.mixer.Sound):
    def __init__(self):                    
        pygame.mixer.Sound.__init__(self, os.path.join(RESOURCE_DIR, 'boing.wav'))        

def main():
    game = Game(caption='Chico The Chimp', screen_size=DEFAULT_SCREEN_SIZE)
    game.loop()

if __name__ == '__main__':
    main() 
